package gov.nhso.prov.acc.sap;


import gov.nhso.prov.acc.beans.Acc6ProvinceAccountBean;
import gov.nhso.prov.acc.beans.Acc6TransactionBean;
import gov.nhso.prov.acc.beans.Acc6VenderBean;
import gov.nhso.prov.acc.beans.Acc7ProvinceAccountBean;
import gov.nhso.prov.acc.beans.Acc7TransactionBean;
import gov.nhso.prov.acc.core.ConfigBundle;
import gov.nhso.prov.acc.core.DBConnection;
import gov.nhso.prov.acc.utils.DateUtil;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import com.isud.core.ISUD;
import com.isud.core.ISUDFactory;
import com.sap.mw.jco.IRepository;
import com.sap.mw.jco.JCO;

/**
 * Example of a JCo server with transaction processing
 * This is an example of the simplest implementation
 * of a JCo dual server. It uses dynamic repositories
 * for each of the servers.
 *
 * Property of SAP AG, Walldorf
 * (c) Copyright SAP AG, Walldorf, 2000-2003.
 * All rights reserved.
 *
 * @version  1.1
 * @author   SAP AG, Walldorf
 */

@SuppressWarnings("unchecked")
//******************************************************************************
public class JCOServer32 implements JCO.ServerExceptionListener, JCO.ServerErrorListener {
//******************************************************************************

	private static String client = ConfigBundle.getValue("SAP_CLIENT");
	private static String userid = ConfigBundle.getValue("SAP_USERID");
	private static String passwd = ConfigBundle.getValue("SAP_PASSWD");
	private static String language = ConfigBundle.getValue("SAP_LANGUAGE");
	private static String host = ConfigBundle.getValue("SAP_HOST");
	private static String sysnr = ConfigBundle.getValue("SAP_SYSNR");
	private static String sapgw = ConfigBundle.getValue("SAP_GATEWAY");
	private static String progidAcc = ConfigBundle.getValue("PROGID_ACC");
	private static String progidVender = ConfigBundle.getValue("PROGID_VERNDER");
	
	private static int MAX_SERVERS = 3;
	private static final Server servers[] = new Server[MAX_SERVERS];
	/**
	 *  This is the actual Server (Listener) object
	 */
	static public class Server extends JCO.Server {

		/**
		 *  Simple constructor. Just call superclass to initialize everything
		 *  properly.
		 */
		
		public Server(String gwhost, String gwserv, String program_id, IRepository repos)
		{
			super(gwhost, gwserv, program_id, repos);
		}

		/**
		 *  This function will be invoked when a transactional RFC is being called from a
		 *  SAP R/3 system. The function has to store the TID in permanent storage and return <code>true</code>.
		 *  The method has to return <code>false</code> if the a transaction with this ID has already
		 *  been process. Throw an exception if anything goes wrong. The transaction processing will be
		 *  aborted thereafter.<b>
		 *  Derived servers must override this method to actually implement the transaction ID management.
		 *  @param tid the transaction ID
		 *  @return <code>true</code> if the ID is valid and not in use otherwise, <code>false</code> otherwise
		 */
		protected boolean onCheckTID(String tid)
		{
			return true;
		}

		/**
		 *  This function will be called after the <em>local</em> transaction has been completed.
		 *  All resources assiciated with this TID can be released.<b>
		 *  Derived servers must override this method to actually implement the transaction ID management.
		 *  @param tid the transaction ID
		 */
		protected void onConfirmTID(String tid)
		{
		}

		/**
		 *  This function will be called after <em>all</em> RFC functions belonging to a certain transaction
		 *  have been successfully completed. <b>
		 *  Derived servers can override this method to locally commit the transaction.
		 *  @param tid the transaction ID
		 */
		protected void onCommit(String tid)
		{
		}

		/**
		 *  This function will be called if an error in one of the RFC functions belonging to
		 *  a certain transaction has occurred.<b>
		 *  Derived servers can override this method to locally rollback the transaction.
		 *  @param tid the transaction ID
		 */
		protected void onRollback(String tid)
		{
		}

		/**
		 *  Called upon an incoming requests
		 */
		protected void handleRequest(JCO.Function function)
		{
			String funcName = function.getName();
			Connection conn = null;
    		ISUD dao = null;
    		try {
    			conn = DBConnection.getConnection();
    			dao = ISUDFactory.create(conn);
    			System.out.println(" *** SAP request function name [" + funcName + "]");
    			 if (funcName.equals("ZCREATE_VENDOR")) {
 	            	JCO.Table tbl = function.getTableParameterList().getTable("T_VENDOR");
 	            	for (int i = 0; i < tbl.getNumRows(); i++) {
 	        			tbl.setRow(i);
 	        			String LIFNR = tbl.getString("LIFNR");
 	        		    String BUKRS = tbl.getString("BUKRS");
 	        		    String NAME1 = tbl.getString("NAME1");
 	        		    String NAME2 = tbl.getString("NAME2");
 	        		    String NAME3 = tbl.getString("NAME3");
 	        		    String NAME4 = tbl.getString("NAME4");
 	        		    String PROVINCE_ID = tbl.getString("PROVINCE_ID");
 	        		    String BANKN = tbl.getString("BANKN");
 	        		    String KOINH = tbl.getString("KOINH");
 	        		    String BANKL = tbl.getString("BANKL");
 	        		    String VENDOR_FLAG = tbl.getString("VENDOR_FLAG");
 	        		    if (BUKRS.equals("2000")) {
 	        		    	if (VENDOR_FLAG.equals("P")) {
	 		        		    Acc6ProvinceAccountBean pv = new Acc6ProvinceAccountBean();
	 				    		pv.setProvinceVenderCode(LIFNR);
	 				    		pv.setProvinceVenderName(NAME1 + NAME2 + NAME3 + NAME4);
	 				    		String provinceName = pv.getProvinceVenderName().replaceAll("สำนักงานสาธารณสุขจังหวัด", "");
	 				    		provinceName = provinceName.replaceAll("สสจ.", "");
	 				    		pv.setProvinceName(provinceName);
	 				    		pv.setProvinceId(PROVINCE_ID);
	 				    		pv.setProvinceAccountSaving(BANKN);
	 				    		pv.setProvinceAccountName(KOINH);
	 		        		    dao.insert(pv);
 	        		    	} else {
	 	        		    	Acc6VenderBean v = new Acc6VenderBean();
	 				    		v.setVenderCode(LIFNR);
	 				    		v.setVenderName(NAME1 + NAME2 + NAME3 + NAME4);
	 				    		v.setVenderType("M");
	 				    		v.setProvinceId(PROVINCE_ID);
	 				    		v.setVenderAccount(BANKN);
	 				    		v.setVenderAccountNameTh(KOINH);
	 				    		v.setVenderBankCode(BANKL);
	 				    		String branchCode = "";
	 				    		if (BANKN.trim().length() == 10) {
									branchCode = "0" + BANKN.substring(0, 3);
								} else if (BANKN.trim().length() == 12) {
									branchCode = "0" + BANKN.substring(2, 5);
								}
	 				    		v.setVenderBankBranchCode(branchCode);
	 		        		    dao.insert(v);
 	        		    	}
 	        		    } else {
 	        		    	Acc7ProvinceAccountBean pv = new Acc7ProvinceAccountBean();
 				    		pv.setProvinceVenderCode(LIFNR);
 				    		pv.setProvinceVenderName(NAME1 + NAME2 + NAME3 + NAME4);
 				    		pv.setProvinceName(pv.getProvinceVenderName().replaceAll("สำนักงานสาขาจังหวัด", ""));
 				    		if (!pv.getProvinceName().equals("บึงกาฬ")) {
 					    		String provinceId = dao.chkData(dao.findDataSql("SELECT PROVINCE_ID FROM " + ConfigBundle.getValue("SCHEMA") + ".PROVINCE WHERE PROVINCE_NAME = '" + pv.getProvinceName() + "' ").get("PROVINCE_ID"));
 								pv.setProvinceId(provinceId);
 				    		} else {
 				    			pv.setProvinceId("0038");
 				    		}
 				    		pv.setProvinceAccount(BANKN);
 				    		pv.setProvinceAccountName(KOINH);
 		        		    dao.insert(pv);
 	        		    }
 	            	}
 	            } else if (funcName.equals("ZPOST_ACC_DOC6_OUT") || funcName.equals("ZPOST_ACC_DOC7_OUT")) {
 		            	JCO.Client mConnection = JCO.createClient(JCOServer32.client, JCOServer32.userid, JCOServer32.passwd, JCOServer32.language, JCOServer32.host, JCOServer32.sysnr);
 		            	mConnection.connect();
 		            	
 		            	JCO.Table out = function.getTableParameterList().getTable("T_OUTPUT");
 		            	JCO.Table tbl = function.getTableParameterList().getTable("T_HEADER");
 		            	out.appendRows(tbl.getNumRows());
 		            	for (int i = 0; i < tbl.getNumRows(); i++) {
 		        			tbl.setRow(i);
 		        		    if (i > 0) {
 		        		    	out.nextRow();
 		        		    }
 		        		    String AUGGJ = tbl.getString("AUGGJ");
 		        		    String DOC_DATE = tbl.getString("DOC_DATE");
 		        		    String AMOUNT = tbl.getString("AMOUNT");
 		        		    String BELNR = tbl.getString("BELNR");
 		        		    String LIFNR = tbl.getString("LIFNR");
 		        		    
 		        		    String BUKRS = tbl.getString("BUKRS");
 		        		    String GJAHR = tbl.getString("GJAHR");
 		        		    String STJAH = "";
 		        		    String ZUONR = "";
 		        		    String BUDGET_CODE = "";
 		        		    String STBLG = "";
 		        		    String AUGBL = "";
 		        		    if (funcName.equals("ZPOST_ACC_DOC6_OUT")) {
	 		        		    ZUONR = tbl.getString("ZUONR"); // 6
	 		        		    BUDGET_CODE = tbl.getString("BUDGET_CODE"); //6
 	 		        		    STBLG = tbl.getString("STBLG");
 	 		        		    AUGBL = tbl.getString("AUGBL");
 	 		        		    STJAH = tbl.getString("STJAH");
 		        		    }
 		        		    String REFERENCE = tbl.getString("REFERENCE");
 		        		    String ZDONE = tbl.getString("ZDONE");
 		        		    
	        		    	DateUtil d = new DateUtil();
 		        		    String ts = d.getCurrentTimeStamp2DB();
 		        		    String reason = "";
 		        		    if (funcName.equals("ZPOST_ACC_DOC6_OUT")) {
 		        		    	reason = funcAccDoc6(dao, d, LIFNR, ts, AUGGJ, BUDGET_CODE, DOC_DATE, AMOUNT, BELNR, AUGBL, STBLG, STJAH);
 		        		    } else if (funcName.equals("ZPOST_ACC_DOC7_OUT")) {
 		        		    	reason = funcAccDoc7(dao, d, LIFNR, ts, AUGGJ, DOC_DATE, AMOUNT, BELNR);
 		        		    }
 		        		    
 		        		    if (!reason.equals("")) {
	 							out.setValue(BUKRS, "BUKRS");
	 							out.setValue(AUGGJ, "AUGGJ");
	 							out.setValue(DOC_DATE, "DOC_DATE");
	 							out.setValue(LIFNR, "LIFNR");
	 							out.setValue(BELNR, "BELNR");
	 							out.setValue(GJAHR, "GJAHR");
	 							if (funcName.equals("ZPOST_ACC_DOC6_OUT")) {
		 							out.setValue(ZUONR, "ZUONR");
		 							out.setValue(BUDGET_CODE, "BUDGET_CODE");
		 							out.setValue(STBLG, "STBLG");
		 							out.setValue(AUGBL, "AUGBL");
		 							out.setValue(STJAH, "STJAH");
	 							}
	 							out.setValue(AMOUNT, "AMOUNT");
	 							out.setValue(REFERENCE, "REFERENCE");
	 							out.setValue(ts, "DOCNO_WEB");
	 							if (reason.length() > 255) {
	 								reason = reason.substring(0, 255);
	 							}
	 							out.setValue(reason, "REASON");
	 							out.setValue(ZDONE, "ZDONE");
 		        		    }
 		            	}
 		            	mConnection.execute(function);
 		            	mConnection.disconnect();
 	            }
	            conn.commit();
    		} catch (Exception e) {
    			try {
    				if (conn != null) {
    					conn.rollback();
    				}
    			} catch (SQLException eSQL) {
    				eSQL.printStackTrace();
    			}
    		    
    			e.printStackTrace();
    		} finally {
    			try {
    				if (conn != null) {
    					conn.close();
    				}
    				dao = null;
    			} catch (SQLException e) {
    				e.printStackTrace();
    			}
    		}
		}
	}
	private static String funcAccDoc6(ISUD dao, DateUtil d, String LIFNR, String ts, String AUGGJ, String BUDGET_CODE, String DOC_DATE, String AMOUNT, String BELNR, String AUGBL, String STBLG, String STJAH) {
		String reason = "";
		boolean isFinish = false;
		try {
			Acc6TransactionBean transaction = new Acc6TransactionBean();
 		    String venderCode = LIFNR;
 		    String docReverse = STBLG;
 		    String budgetYear = STJAH;
 		    String strBudgetYear = BUDGET_CODE.substring(0, 2);
 		    Map<String, String> map = new HashMap<String, String>();
 		    
 		    transaction.setTransactionType("S");
 		    transaction.setBudgetYear("25"+strBudgetYear);
 		    transaction.setVenderCode(venderCode);
 		    String provinceId = dao.chkData(dao.findDataSql("SELECT PROVINCE_ID FROM " + ConfigBundle.getValue("SCHEMA") + ".ACC6_PROVINCE_ACCOUNT WHERE PROVINCE_VENDER_CODE = '" + venderCode + "' ").get("PROVINCE_ID"));
 		    transaction.setProvinceId(provinceId);
 		    transaction.setAllocateCode(BUDGET_CODE);
 		    transaction.setIncomeDate(d.changeDateSapToDB(DOC_DATE));
 		    transaction.setIncomeAmount(AMOUNT);
 		    transaction.setRefNo(BELNR);
 		    transaction.setChqStmtKey(AUGBL);
 		    transaction.setReasonCode("00");
 		    
			if (docReverse != null && !docReverse.equals("")) {
				StringBuffer sb = new StringBuffer();
				sb.append("SELECT TO_CHAR(TRANSACTION_TIMESTAMP, 'YYYYMMDDHH24MISSFF3') AS TRANSACTION_TIMESTAMP ");
				sb.append("FROM ACC6_TRANSACTION ");
				sb.append("WHERE CHQ_STMT_KEY = '" + docReverse + "'  AND BUDGET_YEAR = '" + String.valueOf(Integer.parseInt(budgetYear) + 543) + "' ");
				sb.append("AND TRANSACTION_TYPE = 'S' ");
				map = dao.findDataSql(sb.toString());
				if (!dao.chkData(map.get("TRANSACTION_TIMESTAMP")).equals("")) {
					transaction.setTransactionTimestamp("TO_TIMESTAMP('" + dao.chkData(map.get("TRANSACTION_TIMESTAMP")) + "', 'YYYYMMDDHH24MISSFF3')");
		 		    dao.delete(transaction);
		 		    isFinish = true;
				}
			} else {
	 		    transaction.setTransactionTimestamp(d.setTimeStamp2DB(ts));
	 		    dao.insert(transaction);
	 		    isFinish = true;
			}
 		    dao.beanDebuger(transaction);
 		    if (isFinish) {
 				reason = "SUCCESS";
 		    }
		} catch (Exception e) {
			dao.printMessage();
			reason = dao.getMessage();
		}
		return reason;
	}
	
	private static String funcAccDoc7(ISUD dao, DateUtil d, String LIFNR, String ts, String AUGGJ, String DOC_DATE, String AMOUNT, String BELNR) {
		String reason = "";
		try {
			Acc7TransactionBean transaction = new Acc7TransactionBean();
 		    String venderCode = LIFNR;
 		    transaction.setTransactionTimestamp(d.setTimeStamp2DB(ts));
 		    transaction.setTransactionType("S");
 		    transaction.setBudgetYear(String.valueOf(Integer.parseInt(AUGGJ) + 543));
 		    transaction.setVenderCode(venderCode);
 		    String provinceId = dao.chkData(dao.findDataSql("SELECT PROVINCE_ID FROM " + ConfigBundle.getValue("SCHEMA") + ".ACC7_PROVINCE_ACCOUNT WHERE PROVINCE_VENDER_CODE = '" + venderCode + "' ").get("PROVINCE_ID"));
 		    transaction.setProvinceId(provinceId);
 		    transaction.setIncomeDate(d.changeDateSapToDB(DOC_DATE));
 		    transaction.setIncomeAmount(AMOUNT);
 		    transaction.setRefNo(BELNR);
 		    transaction.setReasonCode("00");
 		    dao.insert(transaction);
			reason = "SUCCESS";
		} catch (Exception e) {
			reason = dao.getMessage();
		}
		dao.printMessage();
		return reason;
	}

	/**
	 *  Called if an exception was thrown anywhere in our server
	 */
	public void serverExceptionOccurred(JCO.Server srv, Exception ex)
	{
		System.out.println("Exception in Server " + srv.getProgID() + ":\n" + ex);
		ex.printStackTrace();
	}

	/**
	 *  Called if an error was thrown anywhere in our server
	 */
	public void serverErrorOccurred(JCO.Server srv, Error err)
	{
		System.out.println("Error in Server " + srv.getProgID() + ":\n" + err);
		err.printStackTrace();
	}

	// System IDs of the system that we gonna using be for dictionary calls
	String POOL_A = "ZCREATE_VENDOR";
	String POOL_B = "ZPOST_ACC_DOC6_OUT";
	String POOL_C = "ZPOST_ACC_DOC7_OUT";

	// The server objects that actually handles the request

	/**
	 *  Constructor. Creates a client pool, the repository and a server.
	 */
	@SuppressWarnings("deprecation")
	public JCOServer32()
	{

		IRepository repository;

		// Add a connection pool to a remote R/3 system A.
		// We will use this connected to dynamically
		// request dictionary information for incoming function calls.
		// !!! Please, fill in the necessary login and system parameters !!!
		JCO.addClientPool(POOL_A,3,client, userid, passwd, language, host, sysnr);

		// Create repository for System A
		repository = JCO.createRepository("ZCREATE_VENDOR", POOL_A );

		// Create a new server and register it with system A
		servers[0] = new Server(host, sapgw, progidVender, repository);

		// Add a connection pool to a remote R/3 system B.
		// We will use this connected to dynamically
		// request dictionary information for incoming function calls.
		// !!! Please, fill in the necessary login and system parameters !!!
		JCO.addClientPool(POOL_B,3,client, userid, passwd, language, host, sysnr);

		// Create repository for system B
		repository = JCO.createRepository("ZPOST_ACC_DOC6_OUT", POOL_B );

		// Create a new server and register it with system B
		servers[1] = new Server(host, sapgw, progidAcc, repository);
		
		JCO.addClientPool(POOL_C,3,client, userid, passwd, language, host, sysnr);

		// Create repository for system B
		repository = JCO.createRepository("ZPOST_ACC_DOC7_OUT", POOL_C );

		// Create a new server and register it with system B
		servers[2] = new Server(host, sapgw, progidAcc, repository);

		// Register ourselves such that we get exceptions from the servers
		JCO.addServerExceptionListener(this);

		// Register ourselves such that we get errors from the servers
		JCO.addServerErrorListener(this);
	}

	/**
	 *  Start the server
	 */
	public void startServers()
	{
		try {
			for (int i = 0; i < MAX_SERVERS; i++) {
				if (servers[i].isAlive()) {
					System.out.println(" *** jco server[" + i + "] stop !!! ");
					servers[i].stop();
				}
				servers[i].start();
				System.out.println(" *** jco server[" + i + "] start !!! ");
			}
		}
		catch (Exception ex) {
			System.out.println("Could not start servers !\n" + ex);
		}//try
	}

	/**
	 *  Simple main program driver
	 */
	public static void main(String[] argv)
	{
		JCOServer32 obj = new JCOServer32();
		obj.startServers();
	}
}

